programming4us
           
 
 
Applications Server

Microsoft Dynamics AX 2009 : Working with Forms - Creating dynamic menu buttons

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
7/17/2011 9:15:13 AM
Normally, Dynamics AX forms are created in AOT by adding various controls to the form's design and do not change during runtime. But besides that, Dynamics AX allows developers to add controls dynamically during form runtime.

Probably, you have already noticed that the Document handling form in the standard Dynamics AX application has a nice option to create a new record by clicking the New button and selecting the desired document type from the list. This feature does not add any new functionality to the application, but it provides an alternative way of quickly creating a new record and it makes the form more user-friendly. The content of this button is actually generated dynamically during the initialization of the form and may vary depending on the document handling setup.

There might be other cases when such features can be used. For example, dynamic menu buttons could be used to display a list of statuses, which depends on the type of the selected record.

In this recipe, we will explore the code behind this feature. As an example, we will modify the Ledger budget button on the Chart of accounts form to display a list of available budget models relevant only for the selected ledger account. That means the list is going to be generated dynamically and may be different for different accounts.

How to do it...

  1. 1. Open the LedgerTable form in AOT.

  2. 2. Add the following variable to its class declaration:

    Map modelMap;
  3. 3. Delete the ButtonBudget menu item button located in the form's ButtonGroup.

  4. 4. Create a new button of type MenuButton instead in the same place as ButtonBudget with the following properties:

    Property Value
    Name ButtonBudget
    AutoDeclaration Yes
    Text Ledger budget

  1. 5. Override its clicked() method:

    void clicked()

    {
    MapIterator mapIterator;
    BudgetModel model;
    LedgerBudget budget;
    FormFunctionButtonControl menuItemButton;
    ;
    if (modelMap)
    {
    mapIterator = new MapIterator(modelMap);
    mapIterator.begin();
    while (mapIterator.more())
    {
    element.design().removeControl(mapIterator.key());
    mapIterator.next();
    }
    }
    modelMap = new Map(Types::Integer, Types::String);
    while select model
    where model.Type == HeadingSub::Heading
    && model.Blocked == NoYes::No
    exists join budget
    where budget.ModelNum == model.ModelId
    && budget.AccountNum == LedgerTable.AccountNum
    {
    menuItemButton = ButtonBudget.addControl(
    FormControlType::MenuFunctionButton,
    'LedgerBudgetModel');
    menuItemButton.text(model.Txt);
    modelMap.insert(menuItemButton.id(), model.ModelId);
    }
    super();
    }


  2. 6. Add a new MenuItemButton to this MenuButton with properties:

    Property Value
    Name LedgerBudget
    MenuItemType Display
    MenuItemName LedgerBudget
    Text All models

  1. 7. Insert a Separator afterwards.

  2. 8. The form should look like this in AOT:

  1. 9. Next, add the following code to the top of the form's run() right after the variable declaration section:

    element.controlMethodOverload(true);
  2. 10. And finally, create a new form method:

    public void ledgerBudgetModel_clicked()
    {
    FormFunctionButtonControl menuItemButton;
    BudgetModelId modelId;
    Args args;
    FormRun formRun;
    FormDataSource fds;
    QueryBuildDataSource qbds;
    QueryBuildRange qbr;
    ;
    menuItemButton = element.controlCallingMethod();
    modelId = modelMap.lookup(menuItemButton.id());
    args = new Args(formstr(LedgerBudget));
    args.record(LedgerTable);
    formRun = classfactory.formRunClass(args);
    formRun.init();
    fds = formRun.dataSource();
    dynamic menu buttondynamic menu buttoncreatingqbds = fds.query().dataSourceTable(
    tablenum(LedgerBudget));
    qbr = qbds.addRange(fieldnum(LedgerBudget,ModelNum));
    qbr.value(queryvalue(modelId));
    qbr.status(RangeStatus::Hidden);
    formRun.run();
    formRun.wait();
    }


  3. 11. To test the results, open General ledger | Chart of Account Details, and expand the Ledger budget menu button for several accounts containing budgets for different models. Notice how the content of the Ledger budget menu changes depending on what budgets are configured for the selected account:

  1. 12. If you click on one of the available options, for example, Total Model for account 110110, then you get a list of ledger budget records for this particular account and this particular model:

How it works...

We start the example by adding a new Map variable to the form's class declaration section. We will use it temporarily for storing a list of available budget models along with dynamically created control numbers.

The next step is to replace the existing Ledger budget menu item button with a menu button. This will allow a user to expand it and select one of the options inside it. Notice that the new button is named exactly the same as the previous one. This is because there is a standard code on the form that handles the button's availability depending on the type of selected account. By leaving the same name, we ensure that the code will compile and work properly.

Now, we need to override the button's clicked(). The code in here will be executed once the user has clicked on the Ledger budget button, and it will create dynamic menu item buttons. The code has to be before super() to make sure the super() "knows" about all the controls in this menu button.

The code starts with first removing all existing items, in case they were created previously. We have to perform this operation, otherwise the list will keep increasing with every user click. We loop though the modelMap variable and remove every control from the form's design that matches the value in the Map. This part of the code is not executed when a user opens the Ledger budget menu button for the first time, because modelMap is not initialized yet. After this, we reset the Map by recreating it.

The second part of this method loops through existing budget models for the currently selected ledger account and creates a new menu item button for every model. Here, we also prepare the modelMap variable for further use by storing the number of the newly created control and the budget model ID. Notice that we have set the same name LedgerBudgetModel for every control created. As we will see later, this is done on purpose.

To finish with the Ledger budget menu button, we also add a menu item button pointing to the original Ledger budget form along with a separator. There are two reasons for this. First, we still want to keep the original functionality allowing the user to open the Ledger budget form if there are no budget records. And secondly, by having something inside the Ledger budget menu button, we force it to be displayed during the initialization of the form. If this menu button was empty, it would simply not be displayed on the form and the code in its clicked() method would never be executed. Lastly, the separator simply distinguishes the static and dynamic parts of the content.

Finally, we have to ensure that the correct form is opened once the user selects one of the dynamic options. We could have assigned the LedgerBudget menu item to every control created, but this would not filter the opened Ledger budget form with the chosen budget model. In order to achieve that, we have to override the button's event with our code. By calling controlMethodOverload(true), we enable form control event overriding. Now, we have to create a new form method with a name consisting of the control name and event name separated by an underscore, i.e. for our dynamic control named LedgerBudgetModel, we have to create ledgerBudgetModel_clicked(). In this method, we retrieve the value of the currently selected budget model, create and initialize the LedgerBudget form, apply the budget model filter to its data source, and run it. In this way, we simulate the execution of the LedgerBudget menu item and also set the required filter.

The last thing to mention here is about the security. When building dynamic controls, it is very important that the created functionality can still be properly controlled by the Dynamics AX security system. For example, in this recipe, if a user does not have access to the LedgerBudget menu item, then the Ledger budget menu button will be automatically inaccessible, and there will be no further access to dynamic buttons inside it. This is because during form initialization, only "real" controls are considered so as only the menu button control's LedgerBudget menu item is disabled by the security, the whole menu button will be hidden too.

Other -----------------
- Microsoft Dynamics AX 2009 : Working with Forms - Handling dialog events
- Microsoft Dynamics AX 2009 : Working with Forms - Creating Dialogs
- Performing On-Demand Exchange Server 2003 Monitoring and Maintenance
- Performing Scheduled Exchange Server 2003 Monitoring and Maintenance (part 2) - Using Performance and Protocol Logs and Managing Mailbox Limits
- Performing Scheduled Exchange Server 2003 Monitoring and Maintenance (part 1)
- Microsoft Dynamics GP 2010 : Populating Initial Data - Inventory items
- Organizing Artifacts in BizTalk Server 2009
- Application Lifecycle Management with BizTalk Server 2009
- Exchange Server 2010 : Manage Outlook Client Access (part 2) - Configure Automatic Client Configuration & Configure Access for Third-Party Clients
- Exchange Server 2010 : Manage Outlook Client Access (part 1) - Configure Outlook Anywhere
- Understanding and Installing Active Directory Rights Management Services (part 3)
- Understanding and Installing Active Directory Rights Management Services (part 2) - Installation Procedure
- Understanding and Installing Active Directory Rights Management Services (part 1) - Understanding AD RMS
- Microsoft Dynamics GP 2010 : Populating Initial Data - Open receivables transactions
- Microsoft Dynamics GP 2010 : Populating Initial Data - Customers
- Exchange Server 2010 : Manage Access for Mobile Devices (part 4) - Monitor Mobile Device Usage
- Exchange Server 2010 : Manage Access for Mobile Devices (part 3) - Protect Mobile Devices
- Exchange Server 2010 : Manage Access for Mobile Devices (part 2) - Manage Mobile Device Features and Settings
- Exchange Server 2010 : Manage Access for Mobile Devices (part 1) - Configure Mobile Device Connectivity
- Exchange Server 2010 : Manage Web-Based Email Access (part 2) - Configure OWA Features
 
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
programming4us programming4us